#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>

// initializes an array
void initialize(int * a, int size, int value)
{
	while ( size)
		a[--size] = value;
}

int main(int argc, char * argv[])
{
	// inits MPI
	int mpi_error = MPI_Init(&argc, &argv);
	{
		int process_count = 0;
		int rank = 0;
		
		// retrieves rank and count of processes
		mpi_error = MPI_Comm_size(MPI_COMM_WORLD, &process_count);
		mpi_error = MPI_Comm_rank(MPI_COMM_WORLD, &rank);
		
		printf("Program starts (%d/%d)\n", rank, process_count);
		
		// allocates array
		int * a = (int*)(malloc(process_count*sizeof(int)));
		MPI_Status status;
		
		if ( rank == 0 ) // parent-process
		{
			// parent inits array
			initialize(a, process_count, 0);
			
			// do the work
			a[rank] = rank+1;
			
			// Begin sending jobs
			mpi_error = MPI_Send(a, process_count, MPI_INT, rank+1, 0, MPI_COMM_WORLD);
			
			// Wait for last process to finish 
			mpi_error = MPI_Recv(a, process_count, MPI_INT, process_count-1, 0, MPI_COMM_WORLD, &status);
			
			// assert true results
			int success = 1;
			for(int i = 0; i < process_count; ++i)
			{
				if ( a[i] != i+1 )
				{
					printf("Error at position %d !!!\n", i);
					success = 0;
					break;
				}
			}
			printf("Success: %d\n", success); // 0 -> fail,  1 -> success
		}
		else // child processes
		{
			// wait for start shot
			mpi_error = MPI_Recv(a, process_count, MPI_INT, rank-1, 0, MPI_COMM_WORLD, &status);
			
			// do the work
			a[rank] = rank+1;
			
			// send to the next guy
			mpi_error = MPI_Send(a, process_count, MPI_INT, (rank+1) % process_count, 0, MPI_COMM_WORLD);
		}
		printf("Machine %d of %d finished!\n", rank, process_count);
		
		// deallocates array
		free(a);
	}
	mpi_error = MPI_Finalize(); // destructs MPI environment
	
	return mpi_error;
}
